//! Pomocne funkcije ...

#include "razno.h"

//! operacije s memorijom (preuzeto...)

/*!
 * Popuni blok memorije po bajtovima (8 bita).
 * \param s Blok
 * \param c Vrijednost (samo niskih 8 bita se uzima u obzir)
 * \param n Koliko bajtova treba ispuniti
 * \returns s
 */
void *memset (void *s, int c, size_t n)
{
	size_t p;
	char *m = (char*)s;
	for (p = 0; p < n; ++p, ++m)
		*m = (char)c;
	return s;
}

/*!
 * Popuni blok memorije po word-ovima (16 bita).
 * \param s Blok
 * \param c Vrijednost (samo niskih 16 bita se uzima u obzir)
 * \param n Koliko wordova treba ispuniti
 * \returns s
 */
void *memsetw (void *s, int c, size_t n)
{
	size_t p;
	short *m = (short*)s;
	for (p = 0; p < n; ++p, ++m)
		*m = (short)c;
	return s;
}

/*!
 * Kopira blok memorije po bajtovima (8 bita).
 * \param dest Odrediste
 * \param src Izvor
 * \param n Koliko bajtova treba kopirati
 * \returns dest
 */
void *memcpy (void *dest, const void *src, size_t n)
{
	char *d = (char*)dest, *s = (char*)src;
	size_t p;
	for (p = 0; p < n; ++p, ++d, ++s)
		*d = *s;
	return dest;
}

/*!
 * Pomakne blok memorije po bajtovima (8 bita).
 * \param dest Odrediste
 * \param src Izvor
 * \param n Koliko bajtova treba pomaknuti
 * \returns dest
 */
void *memmove (void *dest, const void *src, size_t n)
{
	char *d, *s;
	size_t p;
	if (dest < src) {
		d = (char*)dest;
		s = (char*)src;
		for (p = 0; p < n; ++p, ++d, ++s)
			*d = *s;
	} else {
		d = ((char*)dest) + n - 1;
		s = ((char*)src) + n - 1;
		for (p = 0; p < n; ++p, --d, --s)
			*d = *s;
	}
	return dest;
}

/*!
 * Pomakne blok memorije po wordovima (16 bita).
 * \param dest Odrediste
 * \param src Izvor
 * \param n Koliko wordova treba pomaknuti
 * \returns dest
 */
void *memmovew (void *dest, const void *src, size_t n)
{
	short int *d, *s;
	size_t p;
	if (dest < src) {
		d = (short int*)dest;
		s = (short int*)src;
		for (p = 0; p < n; ++p, ++d, ++s)
			*d = *s;
	} else {
		d = ((short int*)dest) + n - 1;
		s = ((short int*)src) + n - 1;
		for (p = 0; p < n; ++p, --d, --s)
			*d = *s;
	}
	return dest;
}

/*!
 * Usporedi blokove memorije po bajtovima (8 bita).
 * \param m1 Prvi blok
 * \param m2 Drugi blok
 * \param size Koliko bajtova treba usporediti
 * \returns -1 ako je prvi manji, 0 ako su isti, 1 ako je prvi veci
 */
int memcmp (const void *m1, const void *m2, size_t size)
{
	unsigned char *a = (unsigned char *)m1;
	unsigned char *b = (unsigned char *)m2;
	for (; size--; ++a, ++b) {
		if (*a < *b) return -1;
		else if (*a > *b) return 1;
	}
	return 0;
}


//malo drukcije upravljanje slobodnim/zauzetim elementima polja
//pogledaj "razno.h" za objasnjenje

//za racunanje velicine polja maske
static int velicina_maske(int N) {
	int prvi = N - 1;
	int n = 0;
	while (prvi > 0) {
		prvi >>= 5;
		n += prvi + 1;
	}
	return n;
}
	
//najmanji indeks polja koji je slobodan (ima 1 u najnizoj razini)
int pronadji_bit_32(uint32 *polje, uint32 vel)
{
	int br_razina, n, i, k, prvi;
	
	if (vel < 1 || polje[0] == 0) //ili ne valja velicina ili je sve zauzeto
		return -1;

	br_razina = 1 + bit_scan_backward_asm32(vel - 1) / 5;

	n = 0;	//prvi element razine
	i = 0;	//element razine koji gledam (iz prethodne je razine izracunat)

	for (k = br_razina; k > 0; k--) {
		prvi = bit_scan_forward32(polje[n + i]);
		
		//ovo se ne smije dogoditi, ali ...
		if (prvi == -1) return -1;
		
		i = i * 32 + prvi;
		//svaki element moze pokazivati na 32 u iducoj razini, pa se
		//pri prijelazu u nizu razinu trenutni broj mnozi sa 32 - sada
		//je to indeks odgovarajuceg elementa nize razine (ili bita ako
		//je zadnja razina u pitanju)

		n += 1 + ((vel - 1) >> (k * 5));
		//indeks prvog elementa u iducoj razini
	}

	return i;
}

// N - broj elemenata polja za koje se trazi prazno mjesto, ne velicina od 'p' !
int postavi_bit_32 (uint32 *p, uint32 vel, uint32 bit, bool postavi)
{
	int br_razina, n, i, k, prvi;
	uint32 maska = 0x001f /* 2^5 - 1 ; pet jedinica */;
	
	if (vel < 1) //ne valja velicina
		return -1;

	br_razina = 1 + bit_scan_backward_asm32(vel - 1) / 5;

	n = velicina_maske(vel);//prvi element razmatrane razine (u pocetku iza)

	i = bit;		//element razine koji gledam

	for (k = 1; k <= br_razina; k++) {
		n -= 1 + ((vel - 1) >> (k * 5));
		//oduzmi broj elemenata u razini 'k', n je sada indeks prvog
		//elementa u razini

		prvi = i & maska;	//bit u elementu koji se gleda
		i >>= 5;		//i = indeks elementa u razini

		if (postavi) {
			if ((p[n + i] & (1 << prvi)) != 0)
				break;	//bit je postavljen, pa je sigurno i u
					//nizim razinama: ne idi dalje

			p[n + i] |= 1 << prvi; //postavi bit u 1
		}
		else {
			p[n + i] &= ~(1 << prvi); //postavi bit u 0
			
			if (p[n + i] != 0) //dalje ne brisem, ima neki bit u 1
				break;
		}
	}

	return 0;
}
